package utils

import (
	"archive/zip"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"shape-erver/internal/svc"
	"strings"

	"github.com/gogf/gf/errors/gerror"
	"github.com/gogf/gf/frame/g"
)

var ServerCtx *svc.ServiceContext

func LoadA(ctx *svc.ServiceContext) {
	ServerCtx = ctx

}


func GetTaskStatus(taskId string) string {
	redisKey := "shapeE-task:" + taskId
	varRet, err := g.Redis().DoVar("GET", redisKey)
	if err != nil || varRet.IsNil() {
		return "状态未知"
	}
	status := varRet.String()
	if status == "1" {
		return "正在执行"
	}
	if status == "2" {
		return "任务完成"
	}
	return "状态未知"
}

func RunRender(prompt string, taskGuid string, gpuId int) (string, error) {
	status, _ := GetTaskGuidFromRedis(taskGuid)
	if status == CANCEL {
		fmt.Println("任务已取消")
		return "", gerror.New("任务已取消")
	}
	if status == SUCCESS {
		fmt.Println("任务已完成")
		return "", gerror.New("任务已完成")
	}

	fmt.Println("进到RunRender")
	SetTaskGuidToRedis(taskGuid, PROCESSING)

	pythonPath := g.Cfg().GetString("python_path")
	fmt.Println("pythonPath:", pythonPath)
	script := g.Cfg().GetString("script_file")
	fmt.Println("script:", script)
	args := []string{script, taskGuid, prompt, fmt.Sprintf("%d", gpuId)}
	fmt.Println("args:", args)

	fmt.Println("进到RunRender的go func")
	output, err := exec.Command(pythonPath, args...).Output()
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(string(output))

	//fmt.Println("进到RunRender的go func")
	//output, err := exec.Command(pythonPath, args...).Output()
	//if err != nil {
	//	fmt.Println(err)
	//}
	//fmt.Println(string(output))

	//// 测试获取压缩目标文件信息
	//var files []*utils.TargetFile = make([]*utils.TargetFile, 0)
	//// files, err := ListTargetFiles(files, "./test", "")
	//files, err := utils.ListTargetFiles("E:\\shapeE_server\\output\\b9e57085-ad55-4918-953c-a223c983c3ff", "")
	//if err != nil {
	//	fmt.Println(err)
	//	return
	//}
	//fmt.Println(len(files))
	//for _, file := range files {
	//	fmt.Printf("%s \t => %s \n", file.Path, file.RelativePath)
	//}
	//fmt.Println("\n开始压缩文件：")
	//err = utils.MakeZipFile("E:/shapeE_server/output/b9e57085-ad55-4918-953c-a223c983c3ff/b9e57085-ad55-4918-953c-a223c983c3ff.zip", "E:/shapeE_server/output/b9e57085-ad55-4918-953c-a223c983c3ff")
	//if err != nil {
	//	fmt.Printf("zip file failed: %s \n", err)
	//} else {
	//	fmt.Println("zip file succes")
	//}

	MakeZipFile(g.Cfg().GetString("dir_path")+taskGuid+"/"+taskGuid+".zip", g.Cfg().GetString("dir_path")+taskGuid)

	SetTaskGuidToRedis(taskGuid, SUCCESS)

	return taskGuid, nil

}

// 列出一个文件夹下所有的文件路径

func ListFileALLPath(dirPth string) (files []string, err error) {
	files = make([]string, 0, 30)
	dir, err := os.Open(dirPth)
	if err != nil {
		return files, err
	}
	defer dir.Close()
	names, err := dir.Readdirnames(0)
	if err != nil {
		return files, err
	}
	for _, name := range names {
		files = append(files, dirPth+"/"+name)
	}
	return files, nil
}

func ConvertToURL(path string) string {
	// 将文件路径中的目录部分替换为服务器地址和静态文件服务的路径
	url := strings.Replace(path, g.Cfg().GetString("dir_path"), g.Cfg().GetString("dir_url"), 1)
	// 将路径中的反斜杠替换为斜杠
	url = strings.Replace(url, "\\", "/", -1)
	return url
}

func DoRender(taskGuid string, prompt string, gpuId int) error {
	SetTaskGuidToRedis(taskGuid, QUEUED)
	fmt.Println("进到AddTaskLogic")
	promptTrans, _ := TranslateToENOne(prompt)
	_, err := RunRender(promptTrans, taskGuid, gpuId)
	return err

}

//// 把指定文件夹打包成zip包
//func ZipDir(dirPath, zipFile string) error {
//	//folderToZip := "./folderToZip" // 需要打包的文件夹
//	//outputZip := "./output.zip"    // 输出的zip文件路径
//	return nil
//}

func ZipDir(source string, target string) error {
	fmt.Println("开始打包")
	zipfile, err := os.Create(target)
	if err != nil {
		return err
	}
	defer zipfile.Close()

	archive := zip.NewWriter(zipfile)
	defer func(archive *zip.Writer) {
		err = archive.Close()
		if err != nil {
			fmt.Println(err)
		}
	}(archive)

	filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			fmt.Println("err1", err)
			return err
		}

		header, err := zip.FileInfoHeader(info)
		if err != nil {
			fmt.Println("err2", err)
			return err
		}

		header.Name = strings.TrimPrefix(path, string(filepath.Separator))

		if info.IsDir() {
			header.Name += string(filepath.Separator)
		} else {
			header.Method = zip.Deflate
		}

		writer, err := archive.CreateHeader(header)
		if err != nil {
			fmt.Println("err3", err)
			return err
		}

		if !info.IsDir() {
			file, err := os.Open(path)
			if err != nil {
				fmt.Println("err4", err)
				return err
			}
			defer file.Close()
			_, err = io.Copy(writer, file)
			if err != nil {
				fmt.Println("err5", err)
				return err
			}
		}
		return err
	})
	fmt.Println("打包完成")
	return err
}

// 定义一个结构体，用于存储目标文件
// 专门定义结构体是为了方便存储压缩包中的目录结构
type TargetFile struct {
	Path         string // 目标文件路径
	RelativePath string // 压缩文件的相对路径
}

// 获取指定路径目标压缩文件列表
// path : 压缩目标文件的路径
// relativePath : 在压缩包中的相对路径
func ListTargetFiles(path string, relativePath string) (targetFiles []*TargetFile, err error) {
	targetFiles = make([]*TargetFile, 0)
	finfo, err := os.Stat(path)
	if err != nil {
		return
	}
	// 如果不是目录，则直接将文件加入文件列表
	if !finfo.IsDir() {
		targetFile := &TargetFile{
			Path:         path,
			RelativePath: relativePath + finfo.Name(),
		}
		targetFiles = append(targetFiles, targetFile)
		return
	}
	// 遍历目录
	dstFile, err := os.Open(path)
	if err != nil {
		return
	}
	fileInfos, err := dstFile.Readdir(-1)
	if err != nil {
		return
	}
	for _, fi := range fileInfos {
		if fi.IsDir() {
			files, err := ListTargetFiles(path+"/"+fi.Name(), relativePath+fi.Name()+"/")
			if err != nil {
				return nil, err
			}
			targetFiles = append(targetFiles, files...)
			continue
		}
		targetFile := &TargetFile{
			Path:         path + "/" + fi.Name(),
			RelativePath: relativePath + fi.Name(),
		}
		targetFiles = append(targetFiles, targetFile)
	}
	return
}

// 制作一个zip文件（打包zip）
// dstZipFile : 输出的目标zip文件
// srcPath : 压缩的目标路径，可以是文件也可以是目录
func MakeZipFile(dstZipFile, srcPath string) error {
	targetFiles, err := ListTargetFiles(srcPath, "")
	if err != nil {
		return err
	}
	// 将文件列表添加到压缩文件
	//zipFile, err := os.Create("archive.zip")
	zipFile, err := os.Create(dstZipFile)
	if err != nil {
		return err
	}
	// 创建一个Writer
	zipWriter := zip.NewWriter(zipFile)
	for _, f := range targetFiles {
		objFile, err := os.Open(f.Path)
		if err != nil {
			return err
		}
		// 关闭文件，注意，因为这里的objFile在每个循环中的值不一样
		// 所以这里应该以闭包的形式实现，不应该直接使用defer objFile.Close()
		w, err := zipWriter.Create(f.RelativePath)
		if err != nil {
			return err
		}
		_, err = io.Copy(w, objFile)
		if err != nil {
			return err
		}
		objFile.Close()
	}
	zipWriter.Close()
	//zipFile.Close()
	return nil
}
